package com.example.spring.jpa.specification;

import com.example.spring.jpa.ast.AstNode;
import com.example.spring.jpa.ast.AstStatic;
import com.example.spring.jpa.ast.operation.*;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.text.ParseException;

/**
 * @author: orange
 * @create: 2023-07-23 17:16
 * @description: 递归解析
 */
public class AstRecursion<T> {
    private final OperationOrStaticHandle operationOrStaticHandle;

    public void setRoot(Root<T> root) {
        operationOrStaticHandle.setRoot(root);
    }
    public void setCriteriaBuilder(CriteriaBuilder criteriaBuilder) {
        operationOrStaticHandle.setBuilder(criteriaBuilder);
    }
    public void setCriteriaQuery(CriteriaQuery<?> query) {
        operationOrStaticHandle.setQuery(query);
    }

    public AstRecursion(Class<?> aClass) {
        operationOrStaticHandle
                = new OperationOrStaticHandle(aClass);
    }

    public Predicate exec(String exp) throws Exception {
        AstNode astNode = Calculation.calc(exp);
        if (astNode instanceof AstGrammar) {
            dfs((AstGrammar) astNode);
        }
        operationOrStaticHandle.finish();
        return operationOrStaticHandle.pop();
    }

    private void dfs(AstGrammar grammar) throws ParseException {
        if (grammar == null) return;
        AstNode left = grammar.getLeft();
        AstNode right = grammar.getRight();

        if (grammar instanceof AstBracket) {
            this.operationOrStaticHandle.openBracket();
        }

        if (left instanceof AstGrammar) {
            dfs((AstGrammar) left);
        }

        if (left instanceof AstStatic) {
            this.operationOrStaticHandle.staticExpHandle(left.sentence());
        }

        if (grammar instanceof AstBracket) {
            judgeGrammar(((AstBracket) grammar).getAstGrammar());
        } else {
            judgeGrammar(grammar);
        }

        if (right instanceof AstStatic) {
            this.operationOrStaticHandle.staticExpHandle(right.sentence());
        }

        if (right instanceof AstGrammar) {
            dfs((AstGrammar) right);
        }

        if (grammar instanceof AstBracket) {
            this.operationOrStaticHandle.closeBracket();
        }
    }

    private void judgeGrammar(AstGrammar astGrammar) throws ParseException {
        if (astGrammar instanceof AstDichotomyOperation) {
            this.operationOrStaticHandle.dichotomyHandle(astGrammar.sentence());
        } else if (astGrammar instanceof AstNoDichotomyOperation) {
            this.operationOrStaticHandle.noDichotomyHandle(astGrammar.sentence());
        } else if (astGrammar instanceof AstSymmetryOperation) {
            this.operationOrStaticHandle.symmetryHandle(astGrammar.sentence());
        }
    }
}
